/*
Copyright 2010 Iain Surgey.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

int	a_skinwidth, a_skinstart;

#define DPS_MAXSPANS 	MAXHEIGHT+1	

struct {
	int			pdest;
	int			pz;
	int			count;
	int			ptex;
	int			sfrac, tfrac, light, zi;
	int			u, v;
} spanpackage_t;

spanpackage_t a_spans[DPS_MAXSPANS];

int			d_xdenom;

int	r_p0[6], r_p1[6], r_p2[6];

struct {
	int		isflattop;			//0
	int		numleftedges;		//4
	int		*pleftedgevert0;	//8
	int		*pleftedgevert1;	//12
	int		*pleftedgevert2;	//16
	int		numrightedges;		//20
	int		*prightedgevert0;	//24
	int		*prightedgevert1;	//28
	int		*prightedgevert2;	//32
} edgetable;

edgetable	*pedgetable;

edgetable	edgetables[12];

int				a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole;
int				r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy;
int				r_zistepx, r_zistepy;
int				d_aspancount, d_countextrastep;

int d_pdest, d_ptex;

spanpackage_t			*d_pedgespanpackage;

int d_pz, d_u, d_v;

int						ystart;
int						d_sfrac, d_tfrac, d_light, d_zi;
int						d_ptexextrastep, d_sfracextrastep;
int						d_tfracextrastep, d_lightextrastep, d_pdestextrastep;
int						d_lightbasestep, d_pdestbasestep, d_ptexbasestep;
int						d_sfracbasestep, d_tfracbasestep;
int						d_ziextrastep, d_zibasestep;
int						d_pzextrastep, d_pzbasestep;

#__body__


private function Init_Edgetables() {
	
	#{d| int *et}
	et = #{edgetables};
	
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p0};
	#{et[3] = r_p2};
	#{et[4] = -1};
	#{et[5] = 2};
	#{et[6] = r_p0};
	#{et[7] = r_p1};
	#{et[8] = r_p2};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 2};
	#{et[2] = r_p1};
	#{et[3] = r_p0};
	#{et[4] = r_p2};
	#{et[5] = 1};
	#{et[6] = r_p1};
	#{et[7] = r_p2};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 1};
	#{et[1] = 1};
	#{et[2] = r_p0};
	#{et[3] = r_p2};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p1};
	#{et[7] = r_p2};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p1};
	#{et[3] = r_p0};
	#{et[4] = -1};
	#{et[5] = 2};
	#{et[6] = r_p1};
	#{et[7] = r_p2};
	#{et[8] = r_p0};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 2};
	#{et[2] = r_p0};
	#{et[3] = r_p2};
	#{et[4] = r_p1};
	#{et[5] = 1};
	#{et[6] = r_p0};
	#{et[7] = r_p1};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p2};
	#{et[3] = r_p1};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p2};
	#{et[7] = r_p0};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p2};
	#{et[3] = r_p1};
	#{et[4] = -1};
	#{et[5] = 2};
	#{et[6] = r_p2};
	#{et[7] = r_p0};
	#{et[8] = r_p1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 2};
	#{et[2] = r_p2};
	#{et[3] = r_p1};
	#{et[4] = r_p0};
	#{et[5] = 1};
	#{et[6] = r_p2};
	#{et[7] = r_p0};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p1};
	#{et[3] = r_p0};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p1};
	#{et[7] = r_p2};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 1};
	#{et[1] = 1};
	#{et[2] = r_p2};
	#{et[3] = r_p1};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p0};
	#{et[7] = r_p1};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 1};
	#{et[1] = 1};
	#{et[2] = r_p1};
	#{et[3] = r_p0};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p2};
	#{et[7] = r_p0};
	#{et[8] = -1};
	
	et += #{sizeof(edgetable)};
	#{et[0] = 0};
	#{et[1] = 1};
	#{et[2] = r_p0};
	#{et[3] = r_p2};
	#{et[4] = -1};
	#{et[5] = 1};
	#{et[6] = r_p0};
	#{et[7] = r_p1};
	#{et[8] = -1};
	
}


/*
================
R_PolysetUpdateTables
================
*/
private inline function R_PolysetUpdateTables ()
{
	a_skinwidth = #{r_affinetridesc.skinwidth};
	a_skinstart = #{r_affinetridesc.pskin};
}


/*
================
R_DrawTriangle
================
*/
private function R_DrawTriangle()
{
	#{d| int dv1_ab, dv0_ac}
	#{d| int dv0_ab, dv1_ac}
	
	dv0_ab = #{atriparms_a->u - atriparms_b->u};
	dv1_ab = #{atriparms_a->v - atriparms_b->v};
	
	if ( ( dv0_ab | dv1_ab ) == 0 )
		return;
	
	dv0_ac = #{atriparms_a->u - atriparms_c->u};
	dv1_ac = #{atriparms_a->v - atriparms_c->v};
	
	if ( ( dv0_ac | dv1_ac ) == 0 )
		return;
	
	d_xdenom = ( dv0_ac * dv1_ab ) - ( dv0_ab * dv1_ac );
	
	if ( d_xdenom < 0 )
	{
		#{r_p0[0] = atriparms_a->u};		// u
		#{r_p0[1] = atriparms_a->v};		// v
		#{r_p0[2] = atriparms_a->s};		// s
		#{r_p0[3] = atriparms_a->t};		// t
		#{r_p0[4] = atriparms_a->l};		// light
		#{r_p0[5] = atriparms_a->zi};		// iz
		
		#{r_p1[0] = atriparms_b->u};
		#{r_p1[1] = atriparms_b->v};
		#{r_p1[2] = atriparms_b->s};
		#{r_p1[3] = atriparms_b->t};
		#{r_p1[4] = atriparms_b->l};
		#{r_p1[5] = atriparms_b->zi};
		
		#{r_p2[0] = atriparms_c->u};
		#{r_p2[1] = atriparms_c->v};
		#{r_p2[2] = atriparms_c->s};
		#{r_p2[3] = atriparms_c->t};
		#{r_p2[4] = atriparms_c->l};
		#{r_p2[5] = atriparms_c->zi};
		
		R_PolysetSetEdgeTable ();
		R_RasterizeAliasPolySmooth ();
	}
}

/*
================
R_PolysetSetEdgeTable
================
*/
private function R_PolysetSetEdgeTable ()
{
	#{d| int			edgetableindex}
	
	edgetableindex = 0;	// assume the vertices are already in
						//  top to bottom order
	
//
// determine which edges are right & left, and the order in which
// to rasterize them
//
	if (#{r_p0[1]} >= #{r_p1[1]})
	{
		if (#{r_p0[1]} == #{r_p1[1]})
		{
			if (#{r_p0[1]} < #{r_p2[1]})
				pedgetable = #{&edgetables[2]};
			else
				pedgetable = #{&edgetables[5]};
			
			return;
		}
		else
		{
			edgetableindex = 1;
		}
	}
	
	if (#{r_p0[1]} == #{r_p2[1]})
	{
		if (edgetableindex != 0)
			pedgetable = #{&edgetables[8]};
		else
			pedgetable = #{&edgetables[9]};
		
		return;
	}
	else if (#{r_p1[1]} == #{r_p2[1]})
	{
		if (edgetableindex != 0)
			pedgetable = #{&edgetables[10]};
		else
			pedgetable = #{&edgetables[11]};
		
		return;
	}
	
	if (#{r_p0[1]} > #{r_p2[1]})
		edgetableindex += 2;
	
	if (#{r_p1[1]} > #{r_p2[1]})
		edgetableindex += 4;
	
	pedgetable = #{edgetables + (edgetableindex*sizeof(edgetable))};
}


/*
================
R_RasterizeAliasPolySmooth
================
*/
private inline function R_RasterizeAliasPolySmooth ()
{
	#{d| int				initialleftheight, initialrightheight, height}
	#{d| int				*plefttop, *prighttop, *pleftbottom, *prightbottom}
	#{d| int				working_lstepx, originalcount}
	#{d| spanpackage_t *pstart}
	
	plefttop = #{pedgetable->pleftedgevert0};
	prighttop = #{pedgetable->prightedgevert0};
	
	pleftbottom = #{pedgetable->pleftedgevert1};
	prightbottom = #{pedgetable->prightedgevert1};
	
	initialleftheight = #{pleftbottom[1] - plefttop[1]};
	initialrightheight = #{prightbottom[1] - prighttop[1]};
	
//
// set the s, t, and light gradients, which are consistent across the triangle
// because being a triangle, things are affine
//
	R_PolysetCalcGradients (a_skinwidth);
//
// rasterize the polygon
//
	
//
// scan out the top (and possibly only) part of the left edge
//
	d_pedgespanpackage = #{a_spans};
	
	ystart = #{plefttop[1]};
	d_aspancount = #{plefttop[0] - prighttop[0]};
	
	d_ptex = a_skinstart + (((#{plefttop[2]} >> 16) +
			((#{plefttop[3]} >> 16) * a_skinwidth))<<2);
	
	d_sfrac = #{plefttop[2]} & 0xFFFF;
	d_tfrac = #{plefttop[3]} & 0xFFFF;
	
	d_light = #{plefttop[4]};
	d_zi = #{plefttop[5]};
	
	
	d_u = #{plefttop[0]};
	d_v = ystart;
	d_pdest = ystart * RESH + d_u;
	d_pz = #{ystart * RESH + d_u};
	
	
	if (initialleftheight == 1)
	{
		#{d_pedgespanpackage->pdest = d_pdest};
		#{d_pedgespanpackage->pz = d_pz};
		#{d_pedgespanpackage->count = d_aspancount};
		#{d_pedgespanpackage->ptex = d_ptex};
		
		#{d_pedgespanpackage->sfrac = d_sfrac};
		#{d_pedgespanpackage->tfrac = d_tfrac};
		
	// FIXME: need to clamp l, s, t, at both ends?
		#{d_pedgespanpackage->light = d_light};
		#{d_pedgespanpackage->zi = d_zi};
		
		#{d_pedgespanpackage->u = d_u};
		#{d_pedgespanpackage->v = d_v};

		d_pedgespanpackage+= #{sizeof(spanpackage_t)};
	}
	else
	{
		R_PolysetSetUpForLineScan(#{plefttop[0]}, #{plefttop[1]},
							  #{pleftbottom[0]}, #{pleftbottom[1]});
		
		d_pzbasestep = RESH + ubasestep;
		d_pzextrastep = d_pzbasestep + 1;
		
		d_pdestbasestep = scr_width + ubasestep;
		d_pdestextrastep = d_pdestbasestep + 1;
		
	// TODO: can reuse partial expressions here
		
	// for negative steps in x along left edge, bias toward overflow rather than
	// underflow (sort of turning the floor () we did in the gradient calcs into
	// ceil (), but plus a little bit)
		if (ubasestep < 0)
			working_lstepx = r_lstepx - 1;
		else
			working_lstepx = r_lstepx;
		
		d_countextrastep = ubasestep + 1;
		d_ptexbasestep = (((r_sstepy + r_sstepx * ubasestep) >> 16) +
				((r_tstepy + r_tstepx * ubasestep) >> 16) * a_skinwidth)<<2;
		
		d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
		d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
		
		//d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
		d_zibasestep = r_zistepy + r_zistepx * ubasestep;
		
		d_ptexextrastep = (((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
				((r_tstepy + r_tstepx * d_countextrastep) >> 16) * a_skinwidth)<<2;
		
		d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF;
		d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF;
		
		//d_lightextrastep = d_lightbasestep + working_lstepx;
		d_ziextrastep = d_zibasestep + r_zistepx;
		
		R_PolysetScanLeftEdge_C(initialleftheight);
	}
	
//
// scan out the bottom part of the left edge, if it exists
//
	if (#{pedgetable->numleftedges} == 2)
	{
		plefttop = pleftbottom;
		pleftbottom = #{pedgetable->pleftedgevert2};
		
		height = #{pleftbottom[1] - plefttop[1]};
		
// TODO: make this a function; modularize this function in general
		
		ystart = #{plefttop[1]};
		d_aspancount = #{plefttop[0] - prighttop[0]};
		d_ptex = a_skinstart + (((#{plefttop[2]} >> 16) +
				(#{plefttop[3]} >> 16) * a_skinwidth)<<2);
		d_sfrac = 0;
		d_tfrac = 0;
		d_light = #{plefttop[4]};
		d_zi = #{plefttop[5]};
		
		
		d_u = #{plefttop[0]};
		d_v = ystart;
		d_pdest = #{ystart * scr_width + d_u};
		d_pz = #{ystart * scr_width + d_u};
		
		if (height == 1)
		{
			#{d_pedgespanpackage->pdest = d_pdest};
			#{d_pedgespanpackage->pz = d_pz};
			#{d_pedgespanpackage->count = d_aspancount};
			#{d_pedgespanpackage->ptex = d_ptex};
			
			#{d_pedgespanpackage->sfrac = d_sfrac};
			#{d_pedgespanpackage->tfrac = d_tfrac};
			
		// FIXME: need to clamp l, s, t, at both ends?
			#{d_pedgespanpackage->light = d_light};
			#{d_pedgespanpackage->zi = d_zi};
			
			#{d_pedgespanpackage->u = d_u};
			#{d_pedgespanpackage->v = d_v};
			
			d_pedgespanpackage+=#{sizeof(spanpackage_t)};
		}
		else
		{
			R_PolysetSetUpForLineScan(#{plefttop[0]}, #{plefttop[1]},
								  #{pleftbottom[0]}, #{pleftbottom[1]});
			
			d_pdestbasestep = scr_width + ubasestep;
			d_pdestextrastep = d_pdestbasestep + 1;
			
			d_pzbasestep = RESH + ubasestep;
			d_pzextrastep = d_pzbasestep + 1;
			
			
			if (ubasestep < 0)
				working_lstepx = r_lstepx - 1;
			else
				working_lstepx = r_lstepx;
			
			d_countextrastep = ubasestep + 1;
			d_ptexbasestep = (((r_sstepy + r_sstepx * ubasestep) >> 16) +
					((r_tstepy + r_tstepx * ubasestep) >> 16) * a_skinwidth)<<2;
			
			d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF;
			d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF;
			
			d_lightbasestep = r_lstepy + working_lstepx * ubasestep;
			d_zibasestep = r_zistepy + r_zistepx * ubasestep;

			d_ptexextrastep = (((r_sstepy + r_sstepx * d_countextrastep) >> 16) +
					((r_tstepy + r_tstepx * d_countextrastep) >> 16) * a_skinwidth)<<2;
			
			d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF;
			d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF;
			
			d_lightextrastep = d_lightbasestep + working_lstepx;
			d_ziextrastep = d_zibasestep + r_zistepx;
			
			R_PolysetScanLeftEdge_C(height);
		}
	}

// scan out the top (and possibly only) part of the right edge, updating the
// count field
	d_pedgespanpackage = #{a_spans};

	R_PolysetSetUpForLineScan(#{prighttop[0]}, #{prighttop[1]},
						  #{prightbottom[0]}, #{prightbottom[1]});
	d_aspancount = 0;
	d_countextrastep = ubasestep + 1;
	
	pstart = #{a_spans + (initialrightheight * sizeof(spanpackage_t))};
	
	originalcount = #{pstart->count};  //#{a_spans[initialrightheight].count};
	#{pstart->count = -999999};
	//#{a_spans[initialrightheight].count = -999999}; // mark end of the spanpackages
	
	R_PolysetDrawSpans8_Opaque (#{a_spans});
	
// scan out the bottom part of the right edge, if it exists
	if (#{pedgetable->numrightedges} == 2)
	{		
		pstart = #{a_spans + (initialrightheight * sizeof(spanpackage_t))};
		#{pstart->count = originalcount};
		
		d_aspancount = #{prightbottom[0] - prighttop[0]};
		
		prighttop = prightbottom;
		prightbottom = #{pedgetable->prightedgevert2};
		
		height = #{prightbottom[1] - prighttop[1]};
		
		R_PolysetSetUpForLineScan(#{prighttop[0]}, #{prighttop[1]},
							  #{prightbottom[0]}, #{prightbottom[1]});
		
		d_countextrastep = ubasestep + 1;
		
		//pstart = #{a_spans + ((initialrightheight+height) * sizeof(spanpackage_t))};
		//#{pstart->count = -999999};
		
		#{a_spans[initialrightheight + height].count = -999999};
											// mark end of the spanpackages
		R_PolysetDrawSpans8_Opaque (pstart);
	}
}


private inline function R_PolysetCalcGradients (skinwidth : Int)
{
	#{d| float	xstepdenominv, ystepdenominv, t0, t1}
	#{d| float	p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20}

	p00_minus_p20 = #{r_p0[0] - r_p2[0]};
	p01_minus_p21 = #{r_p0[1] - r_p2[1]};
	p10_minus_p20 = #{r_p1[0] - r_p2[0]};
	p11_minus_p21 = #{r_p1[1] - r_p2[1]};

	xstepdenominv = 1.0 / d_xdenom;

	ystepdenominv = -xstepdenominv;

// ceil () for light so positive steps are exaggerated, negative steps
// diminished,  pushing us away from underflow toward overflow. Underflow is
// very visible, overflow is very unlikely, because of ambient lighting
	t0 = #{r_p0[4] - r_p2[4]};
	t1 = #{r_p1[4] - r_p2[4]};
	r_lstepx = Math.ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv);
	r_lstepy = Math.ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv);

	t0 = #{r_p0[2] - r_p2[2]};
	t1 = #{r_p1[2] - r_p2[2]};
	r_sstepx = Std.int((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
			xstepdenominv);
	r_sstepy = Std.int((t1 * p00_minus_p20 - t0* p10_minus_p20) *
			ystepdenominv);

	t0 = #{r_p0[3] - r_p2[3]};
	t1 = #{r_p1[3] - r_p2[3]};
	r_tstepx = Std.int((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
			xstepdenominv);
	r_tstepy = Std.int((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
			ystepdenominv);

	t0 = #{r_p0[5] - r_p2[5]};
	t1 = #{r_p1[5] - r_p2[5]};
	r_zistepx = Std.int((t1 * p01_minus_p21 - t0 * p11_minus_p21) *
			xstepdenominv);
	r_zistepy = Std.int((t1 * p00_minus_p20 - t0 * p10_minus_p20) *
			ystepdenominv);
	
	a_sstepxfrac = r_sstepx & 0xFFFF;
	a_tstepxfrac = r_tstepx & 0xFFFF;
	
	a_ststepxwhole = a_skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16);
}


/*
===================
R_PolysetSetUpForLineScan
====================
*/
private inline function R_PolysetSetUpForLineScan(startvertu : Int, startvertv : Int,
		endvertu : Int, endvertv : Int)
{
	#{d| float		numer, denom}
	#{d| int			tm, tn, ptemp}
	
	errorterm = -1;
	
	tm = endvertu - startvertu;
	tn = endvertv - startvertv;
	
	if (((tm <= 16) && (tm >= -15)) &&
		((tn <= 16) && (tn >= -15)))
	{
		ptemp = #{adivtab} + ((((tm+15) << 5) + (tn+15))<<1);
		ubasestep = Memory.signExtend8(Memory.getByte(ptemp));
		erroradjustup = Memory.signExtend8(Memory.getByte(ptemp+1));
		erroradjustdown = tn;
	}
	else
	{
		numer = tm;
		denom = tn;
		
		if (numer >= 0.0)
		{
			ubasestep = Math.floor(numer / denom);
			erroradjustup = Math.floor(numer - (ubasestep * denom)); //FIXME: Use modulo
		} else {
			ubasestep = Math.floor(-numer / denom);
			erroradjustup = Math.floor(-numer - (ubasestep * denom));
			ubasestep = -ubasestep;
			if (erroradjustup != 0) {
				ubasestep--;
				erroradjustup = tn - erroradjustup;
			}
		}
		
		erroradjustdown = tn;
	}
}


/*
===================
R_PolysetScanLeftEdge_C
====================
*/
private inline function R_PolysetScanLeftEdge_C(height : Int)
{
	#{s| int height}
	do
	{
		#{d_pedgespanpackage->pdest = d_pdest};
		#{d_pedgespanpackage->pz = d_pz};
		#{d_pedgespanpackage->count = d_aspancount};
		#{d_pedgespanpackage->ptex = d_ptex};
		#{d_pedgespanpackage->sfrac = d_sfrac};
		#{d_pedgespanpackage->tfrac = d_tfrac};
		
	// FIXME: need to clamp l, s, t, at both ends?
		#{d_pedgespanpackage->light = d_light};
		#{d_pedgespanpackage->zi = d_zi};
		
		#{d_pedgespanpackage->u = d_u};
		#{d_pedgespanpackage->v = d_v};
		
		d_pedgespanpackage+=#{sizeof(spanpackage_t)};
		
		errorterm += erroradjustup;
		if (errorterm >= 0)
		{
			d_pdest += d_pdestextrastep;
			d_pz += d_pzextrastep;
			d_aspancount += d_countextrastep;
			d_ptex += d_ptexextrastep;
			d_sfrac += d_sfracextrastep;
			d_ptex += (d_sfrac >> 16)<<2;
			
			d_sfrac &= 0xFFFF;
			d_tfrac += d_tfracextrastep;
			if ((d_tfrac & 0x10000) != 0)
			{
				d_ptex += a_skinwidth<<2;
				d_tfrac &= 0xFFFF;
			}
			//d_light += d_lightextrastep;
			d_zi += d_ziextrastep;
			errorterm -= erroradjustdown;
			
			d_v += 1;
			d_u += ubasestep +1;
		}
		else
		{
			d_pdest += d_pdestbasestep;
			d_pz += d_pzbasestep;
			d_aspancount += ubasestep;
			d_ptex += d_ptexbasestep;
			d_sfrac += d_sfracbasestep;
			d_ptex += (d_sfrac >> 16)<<2;
			d_sfrac &= 0xFFFF;
			d_tfrac += d_tfracbasestep;
			if ((d_tfrac & 0x10000) != 0)
			{
				d_ptex += a_skinwidth<<2;
				d_tfrac &= 0xFFFF;
			}
			//d_light += d_lightbasestep;
			d_zi += d_zibasestep;
			
			d_v += 1;
			d_u += ubasestep;
		}
	} while (--height > 0);
}

private function R_PolysetDrawSpans8_Opaque (pspanpackage : Int) //spanpackage_t *pspanpackage)
{
	#{d| int		lcount,skip, zmin, zmax, newmin, newmax}
	#{d| int lsfrac, ltfrac, lpdest, lptex, _lu, _lv} //llight
	#{d| int lzi, lpz, zval} // lpz
	#{s| spanpackage_t *pspanpackage}
	#{d| int luo, lcounto, zmino}
	
	if (#{pspanpackage->count} != -999999)
	do
	{
		lcount = d_aspancount - #{pspanpackage->count};
		
		errorterm += erroradjustup;
		if (errorterm >= 0)
		{
			d_aspancount += d_countextrastep;
			errorterm -= erroradjustdown;
		}
		else
		{
			d_aspancount += ubasestep;
		}
		
		if (lcount > 0)
		{
			lzi = #{pspanpackage->zi};
			lpdest = #{pspanpackage->pdest};
			lsfrac = #{pspanpackage->sfrac};
			ltfrac = #{pspanpackage->tfrac};
			lptex = #{pspanpackage->ptex};
			_lu = #{pspanpackage->u};
			_lv = #{pspanpackage->v};
			
			//get z buffer bounds
			zval = Memory.getI32(#{zminmaxs}+(_lv<<2));
			if (zval & 0x7FC00000 == r_zmmframe) {
				zmin = (zval & 0x3FF800)>>11;
				zmax = (zval & 0x7FF);
				
				//update bounds
				if (_lu < zmin) newmin = _lu; else newmin = zmin;
				if (_lu+lcount > zmax) newmax = _lu+lcount; else newmax = zmax;
				if (newmin != zmin || newmax != zmax) Memory.setI32(#{zminmaxs}+(_lv<<2),r_zmmframe|newmin<<11|newmax);
				
				if (_lu+lcount < zmin) {
					lpz = #{zbuffer}+(((_lv*RESH) + _lu+lcount)<<1);
					for (i in 0...(zmin-(_lu+lcount))) { Memory.setI16(lpz, 0); lpz += 2; } 
				} else if (_lu > zmax) {
					lpz = #{zbuffer}+(((_lv*RESH) + zmax)<<1);
					for (i in 0...(_lu-zmax)) { Memory.setI16(lpz, 0); lpz += 2; } 
				}
				
			} else {
				//set new bounds
				Memory.setI32(#{zminmaxs}+(_lv<<2),r_zmmframe|_lu<<11|_lu+lcount);
				zmin = 2047;
				zmax = 0;
			}
			
			newmax = _lu+lcount;
			
			lpz = #{zbuffer}+(lpdest<<1);
			lpdest = DRAWOFS1+(lpdest<<2);
			
			if (zmin > _lu+lcount) { zmin = _lu+lcount; zmax = 0; }
			if (zmax > _lu+lcount) { zmax = _lu+lcount; }
			
			while (_lu < zmin) {
				Memory.setI16(lpz,(lzi>>16));
				Memory.setI32(lpdest,Memory.getI32(lptex));
				
				lpdest+=4;
				lzi += r_zistepx;
				lpz+=2;
				lptex += a_ststepxwhole<<2;
				lsfrac += a_sstepxfrac;
				lptex += (lsfrac >> 16)<<2;
				lsfrac &= 0xFFFF;
				ltfrac += a_tstepxfrac;
				if ((ltfrac & 0x10000) != 0)
				{
					lptex += a_skinwidth<<2;
					ltfrac &= 0xFFFF;
				}
				_lu++;
			}
			
			while (_lu < zmax) {
				if (Memory.getUI16(lpz) < (lzi>>16)) {
					Memory.setI16(lpz,(lzi>>16));
					Memory.setI32(lpdest,Memory.getI32(lptex));
				}
				
				lpdest+=4;
				lzi += r_zistepx;
				lpz+=2;
				lptex += a_ststepxwhole<<2;
				lsfrac += a_sstepxfrac;
				lptex += (lsfrac >> 16)<<2;
				lsfrac &= 0xFFFF;
				ltfrac += a_tstepxfrac;
				if ((ltfrac & 0x10000) != 0)
				{
					lptex += a_skinwidth<<2;
					ltfrac &= 0xFFFF;
				}
				_lu++;
			}
			
			while (_lu < newmax) {
				Memory.setI16(lpz,(lzi>>16));
				Memory.setI32(lpdest,Memory.getI32(lptex));
				
				lpdest+=4;
				lzi += r_zistepx;
				lpz+=2;
				lptex += a_ststepxwhole<<2;
				lsfrac += a_sstepxfrac;
				lptex += (lsfrac >> 16)<<2;
				lsfrac &= 0xFFFF;
				ltfrac += a_tstepxfrac;
				if ((ltfrac & 0x10000) != 0)
				{
					lptex += a_skinwidth<<2;
					ltfrac &= 0xFFFF;
				}
				_lu++;
			}
		}
		pspanpackage+=#{sizeof(spanpackage_t)};
	} while (#{pspanpackage->count} > -999999);
}



